#include "ArchivoTerminos.h"

ArchivoTerminos::ArchivoTerminos(const char* filename) :
		Archivo(filename) {
	string s1 = string(filename);
	string s2 = s1.substr(0, s1.length() - 4);
	s2 += ".ind";

	this->i = new IndiceTerminos(s2.c_str());

	this->resetCache();
	this->bl = 0;
}

void ArchivoTerminos::add(string termino, uint32_t nroTermino, float peso) {
	RegistroTermino r(termino, nroTermino, peso);
	unsigned short int numBytes = termino.length() + sizeof(uint32_t)
			+ sizeof(float);

	unsigned int offset = this->tellp();

	if (offset
			== 0|| ((offset / (1024 * 1024)) - BLOCK_SIZE * bl) >= BLOCK_SIZE) {i->add(termino, (uint32_t) offset);
	bl++;
}

	this->write((char*) &numBytes, sizeof(unsigned short int));
	this->write((char*) &r, numBytes);
}

void ArchivoTerminos::fileToCache(unsigned int offset) {
	this->clear();
	this->seekg(offset, ios::beg);

	unsigned short int numBytes;
	this->read((char*) &numBytes, sizeof(unsigned short int));
	RegistroTermino r;

	this->read((char*) &r, numBytes);
	cache.setTermino(r.getTermino());
	cache.setNroTermino(r.getNroTermino());
	cache.setPesoGlobal(r.getPesoGlobal());
}

bool ArchivoTerminos::bufferToCache(char* buf, string s) {
	unsigned int offset = 0;
	unsigned short int numBytes;
	RegistroTermino *r = new RegistroTermino();

	while (offset < strlen(buf)) {
		char* buf1 = new char[sizeof(unsigned short int)];
		memcpy(buf1, &buf[offset], sizeof(unsigned short int));
		numBytes = atoi(buf1);

		offset += sizeof(unsigned short int);
		unsigned int length = numBytes - sizeof(uint32_t) - sizeof(float);
		char* buf2 = new char[length + 1];
		memcpy(buf2, &buf[offset], length);
		buf2[length] = '\0';
		r->setTermino(string(buf2));
		offset += length;
		delete[] buf2;

		if (r->getTermino().compare(s) == 0) {
			cache.setTermino(s);

			char* buf3 = new char[sizeof(uint32_t)];
			memcpy(buf3, &buf[offset], sizeof(uint32_t));
			r->setNroTermino(atoi(buf3));
			cache.setNroTermino(r->getNroTermino());
			offset += sizeof(uint32_t);
			delete[] buf3;

			char* buf4 = new char[sizeof(float)];
			memcpy(buf4, &buf[offset], sizeof(float));
			r->setPesoGlobal(atof(buf4));
			cache.setPesoGlobal(r->getPesoGlobal());
			delete[] buf4;
			return true;
		}

		offset += numBytes;
		delete (r);
		r = new RegistroTermino();
	}

	return false;
}

void ArchivoTerminos::setCache(string termino) {
	uint32_t startOffset, finalOffset, lenghtOffset;

	startOffset = i->getStartOffset(termino);
	finalOffset = i->getFinalOffset(termino);

	if ((startOffset == finalOffset) && startOffset > 0) {
		fileToCache(startOffset);
		return;
	}

	if (startOffset == 0 && finalOffset == 0) {
		resetCache();
		return;
	}

	lenghtOffset = finalOffset - startOffset;
	char* buf = new char[lenghtOffset];

	this->clear();
	this->seekg(startOffset, ios::beg);

	this->read((char*) buf, lenghtOffset);
	bool find;
	find = bufferToCache(buf, termino);
	if (!find)
		resetCache();
}

void ArchivoTerminos::resetCache() {
	cache.setTermino(string(""));
	cache.setNroTermino(0);
	cache.setPesoGlobal(-1);
}

uint32_t ArchivoTerminos::getNroTermino(string termino) {
	if (termino.compare(cache.getTermino()) == 0)
		return cache.getNroTermino();

	this->setCache(termino);
	return cache.getNroTermino();
}

float ArchivoTerminos::getPesoGlobal(string termino) {
	if (termino.compare(cache.getTermino()) == 0)
		return cache.getPesoGlobal();

	this->setCache(termino);
	return cache.getPesoGlobal();
}

ArchivoTerminos::~ArchivoTerminos() {
	delete (i);
	this->close();
}
